  // NUM_REG : number of registers in the register file
  // SEL_WIDTH : number of bits needed to specify a register
  // D_WIDTH : data width
  
module regfile#(parameter NUM_REG = 8, SEL_WIDTH = 3, D_WIDTH = 34, IA_WIDTH=10, LEVEL_WIDTH=1024) 
(
	// outputs for debugging
	output [D_WIDTH-1:0] reg1, 
	output [D_WIDTH-1:0] reg2, 
	output [D_WIDTH-1:0] reg3,
	output [D_WIDTH-1:0] reg4,
	output [D_WIDTH-1:0] reg5,
	output [D_WIDTH-1:0] reg6,
	output [D_WIDTH-1:0] reg7, 
	output [D_WIDTH-1:0] reg8,
		
    input  clk,
    input  wen_i,
    input  [SEL_WIDTH-1 : 0]  wa_i,	 	// address of register to write to
    input  [D_WIDTH-1 : 0]    wd_i, 	// data to be written to wa_i register
    input  [SEL_WIDTH-1 : 0]  ra0_i,
    input  [SEL_WIDTH-1 : 0]  ra1_i,
    input					  start_i,
    input                     done_i,
    input  [IA_WIDTH-1 : 0]   current_addr_i,
    input  [D_WIDTH-1 : 0]    offset_i,
    input                     branch_true_i,
    input					  return_true_i,
    input					  call_true_i,
    input  [LEVEL_WIDTH-1:0]  level_i,
    output [D_WIDTH-1 : 0]    rd0_o,
    output [D_WIDTH-1 : 0]    rd1_o
	
);

////////////////////////////////////////////////////////////////////////
// local parameters

  localparam REGFILE_WIDTH = 1024; // use 8192 later to match the size of dmem
  
////////////////////////////////////////////////////////////////////////
// registers

  // this is the register: 8 registers, 34-bits long
  // reg [D_WIDTH-1:0] registers [NUM_REG-1:0];
  
  // this is the register file: 128 stacks of 8 registers (128 * 8 = 1024), 34-bits long
  reg [D_WIDTH-1:0] regfile [REGFILE_WIDTH-1:0];
 
  // for call instruction
  reg [D_WIDTH-1:0] fp_temp;
  
  // for accessing regfile
  wire [REGFILE_WIDTH-1:0] regfile_0_index_r;
  wire [REGFILE_WIDTH-1:0] regfile_1_index_r;
  wire [REGFILE_WIDTH-1:0] regfile_2_index_r;
  wire [REGFILE_WIDTH-1:0] regfile_3_index_r;
  wire [REGFILE_WIDTH-1:0] regfile_4_index_r;
  wire [REGFILE_WIDTH-1:0] regfile_5_index_r;
  wire [REGFILE_WIDTH-1:0] regfile_6_index_r;
  wire [REGFILE_WIDTH-1:0] regfile_7_index_r;
  
  wire [REGFILE_WIDTH-1:0] wa_index;
  wire [REGFILE_WIDTH-1:0] regfile_wa_index_r;  
  wire [REGFILE_WIDTH-1:0] ra0_index;
  wire [REGFILE_WIDTH-1:0] regfile_ra0_index_r;
  wire [REGFILE_WIDTH-1:0] ra1_index;
  wire [REGFILE_WIDTH-1:0] regfile_ra1_index_r;
  
  
////////////////////////////////////////////////////////////////////////
// assign 
   
   // Start out by reassigning the registers
   // formula for accessing regfile: (level * 8) + register index
   assign regfile_0_index_r = level_i * 1024'd8 + 1024'd0;
   assign regfile_1_index_r = level_i * 1024'd8 + 1024'd1;
   assign regfile_2_index_r = level_i * 1024'd8 + 1024'd2;
   assign regfile_3_index_r = level_i * 1024'd8 + 1024'd3;
   assign regfile_4_index_r = level_i * 1024'd8 + 1024'd4;
   assign regfile_5_index_r = level_i * 1024'd8 + 1024'd5;
   assign regfile_6_index_r = level_i * 1024'd8 + 1024'd6;
   assign regfile_7_index_r = level_i * 1024'd8 + 1024'd7;
   
   // Find the index of the registers r0 and r1 to read & wa_i to write
   assign wa_index[SEL_WIDTH-1:0] = wa_i;
   assign wa_index[REGFILE_WIDTH-1:SEL_WIDTH] = { 1021{1'b0} };
   assign regfile_wa_index_r = level_i * 1024'd8 + wa_index;
   
   assign ra0_index[SEL_WIDTH-1:0] = ra0_i;
   assign ra0_index[REGFILE_WIDTH-1:SEL_WIDTH] = { 1021{1'b0} };
   assign regfile_ra0_index_r = level_i * 1024'd8 + ra0_index;
   
   assign ra1_index[SEL_WIDTH-1:0] = ra1_i;
   assign ra1_index[REGFILE_WIDTH-1:SEL_WIDTH] = { 1021{1'b0} };
   assign regfile_ra1_index_r = level_i * 1024'd8 + ra1_index;
   
 
////////////////////////////////////////////////////////////////////////
// logic
  
  always @(posedge clk)
	begin
		if(wen_i)
			regfile[regfile_wa_index_r] <= wd_i;
		
		// when it's started, set %fp = 0
		if(regfile[regfile_6_index_r] === 34'bx)
			regfile[regfile_6_index_r] <= 34'b0;
		
		// when it's done, set %fp based on the branch conditionals
		if(done_i)
		begin
			if(branch_true_i)		// branch: %fp = %fp - offset
				regfile[regfile_6_index_r] <= regfile[regfile_6_index_r] - offset_i;
				
			else if(return_true_i)	// return: %fp = %fp - 1, doesn't matter
				regfile[regfile_6_index_r] <= regfile[regfile_6_index_r] - 1;
				
			else if(call_true_i) 	// call: %fp = current address - offset
			begin
				fp_temp[IA_WIDTH-1:0] <= current_addr_i - offset_i[10:0];
				fp_temp[D_WIDTH-1:IA_WIDTH] <= { 24{1'b0} };
				regfile[regfile_6_index_r] <= fp_temp;	
			end		
			
			else					// done: %fp = %fp - 1	
				regfile[regfile_6_index_r] <= regfile[regfile_6_index_r] - 1;
		end
		
	end

////////////////////////////////////////////////////////////////////////
// output

  assign rd0_o = regfile[regfile_ra0_index_r]; 
  assign rd1_o = regfile[regfile_ra1_index_r];
  
////////////////////////////////////////////////////////////////////////
// output: debug

  assign reg1 = regfile[regfile_0_index_r];
  assign reg2 = regfile[regfile_1_index_r];
  assign reg3 = regfile[regfile_2_index_r];
  assign reg4 = regfile[regfile_3_index_r];
  assign reg5 = regfile[regfile_4_index_r];
  assign reg6 = regfile[regfile_5_index_r];
  assign reg7 = regfile[regfile_6_index_r];
  assign reg8 = regfile[regfile_7_index_r];

////////////////////////////////////////////////////////////////////////

endmodule